﻿using MiniFox.Components;
using MiniFox.Exceptions;
using MiniFox.Infrastructure;
using MiniFox.Platform.Exceptions;
using MiniFox.Platform.File.Models;
using MiniFox.Platform.File.Providers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace MiniFox.Platform.File.Services
{
    /// <summary>
    /// 
    /// </summary>
    public class FolderService : FileSystemBase, IFolderService
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="group"></param>
        public FolderService(string group) : base(group)
        {
        }
        /// <summary>
        /// 
        /// </summary>
        [AutoWired]
        protected IFolderProvider Provider { get; set; }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="path"></param>

        private void CheckFolderExists(string path)
        {
            path = string.IsNullOrWhiteSpace(path) ? "/" : path;
            if (path != "/")
                path = $"/{path.Trim('/')}/";
            if (!Provider.PathExists(this.Group, path))
            {
                throw new MiniFox.Exceptions.SystemException(Resources.ExceptionMessages.FolderNotExists);
            }
        }
        /// <summary>
        /// 检查指定路径是否已存在
        /// </summary>
        /// <param name="path">指定路径</param>
        /// <returns></returns>
        public void CheckFolderAvaliable(string path = "/")
        {
            if (path != "/")
                path = $"/{path.Trim('/')}/";
            if (Provider.PathExists(this.Group, path))
            {
                throw new MiniFox.Exceptions.SystemException(Resources.ExceptionMessages.FolderExists);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="folderName"></param>
        /// <param name="superPath"></param>
        /// <returns></returns>
        public FolderObject Create(string folderName, string superPath = "/")
        {
            this.CheckFolderExists(superPath);
            folderName = folderName.Trim('/');
            var path = $"{superPath}{folderName}/";
            CheckFolderAvaliable(path);

            var folderId = SequenceGUID.NewGUID();
            var super = this.Provider.GetFolder(this.Group, superPath);
            if (Provider.Create(this.Group, folderId, folderName, path, super.FolderId))
                return new()
                {
                    FolderId = folderId,
                    FolderName = folderName,
                    CreateTime = DateTime.Now,
                    UpdateTime = DateTime.Now,
                    Group = this.Group,
                    Ordinal = 0,
                    SuperId = super.FolderId,
                    Path = path
                };
            return null;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="folderId"></param>
        /// <param name="superPath"></param>
        /// <returns></returns>
        public FolderObject Move(string folderId, string superPath = "/")
        {
            this.CheckFolderExists(superPath);
            if (Provider.Move(this.Group, folderId, superPath))
                return this.Provider.GetFolder(folderId);
            return null;
        }
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="folderId"></param>
        ///// <param name="superPath"></param>
        ///// <returns></returns>
        //public FolderObject Copy(string folderId, string superPath)
        //{
        //    this.CheckFolderExists(superPath);
        //    if (!Provider.PathExists(this.Group, superPath))
        //        return null;
        //    string newFolderId = SequenceGUID.NewGUID();
        //    if (Provider.Copy(this.Group, newFolderId, folderId, superPath))
        //        return this.Provider.GetFolder(folderId);
        //    return null;
        //}
        /// <summary>
        /// 
        /// </summary>
        /// <param name="path"></param>
        /// <param name="folderName"></param>
        /// <returns></returns>
        public FolderObject Rename(string path, string folderName)
        {
            this.CheckFolderExists(path);
            folderName = folderName.Trim('/');
            if (Provider.Rename(this.Group, path, folderName))
                return this.Provider.GetFolder(path);
            return null;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="path"></param>
        /// <exception cref="PlatformException"></exception>
        public void Remove(string path)
        {
            this.CheckFolderExists(path);
            if (!Provider.Remove(this.Group, path))
                throw new PlatformException("ERR_OperateFail");
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="folderId"></param>
        /// <returns></returns>
        public ZipFileData Zip(string folderId)
        {
            FolderObject folder = this.Provider.GetFolder(folderId);
            if (folder == null) return null;

            using (FileCompressor fileCompressor = new(folder.FolderName))
            {
                IEnumerable<FolderObject> folders = this.Provider.GetAllFolders(this.Group, folder.Path);
                foreach (var f in folders)
                {
                    AddToCompress(f, fileCompressor);
                }
                return fileCompressor.GetResult();
            }
        }

        private void AddToCompress(FolderObject folder, FileCompressor fileCompressor)
        {
            fileCompressor.AddFileToCompress(new PackFile
            {
                FileId = folder.FolderId,
                FileName = folder.FolderName,
                Path = folder.Path,
                CreateTime = folder.CreateTime,
                UpdateTime = folder.UpdateTime,
                Group = folder.Group
            });
            IEnumerable<FileData> fileDatas = folder.Files;
            foreach (FileData fileData in fileDatas)
            {
                PackFile packFile = new PackFile();
                packFile.FileName = fileData.FileName;
                packFile.Data = fileData.Data;
                packFile.Path = fileData.FullName;
                packFile.Group = fileData.Group;
                packFile.CreateTime = fileData.CreateTime;
                packFile.UpdateTime = fileData.UpdateTime;
                fileCompressor.AddFileToCompress(packFile);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public FolderObject GetFolder(string path = "/")
        {
            try
            {
                this.CheckFolderExists(path);
            }
            catch //如果目录不存在
            {
                if (path != "/") return null;
                //初始化根目录
                var folderId = SequenceGUID.NewGUID();
                if (!this.Provider.Create(this.Group, folderId, string.Empty, path, this.Group))
                    return null;
            }
            var folder = this.Provider.GetFolder(this.Group, path);
            return folder;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public object Query(string path = "/")
        {
            var folder = this.GetFolder(path);
            if (folder == null) return null;
            var super = this.Provider.GetFolder(folder.SuperId);
            var children = this.Provider.GetFolders(folder.FolderId);
            object result = new
            {
                super,
                folder,
                children
            };
            return result;
        }
    }
}
